﻿#region zh-CHS 2006 - 2007 DemoSoft 团队 | en 2006 - 2007 DemoSoft Team

//     NOTES
// ---------------
//
// This file is a part of the G.O.S.E(Game Online Server Engine) for .NET.
//
//                 2006-2007 DemoSoft Team
//
//
// First Version : by H.Q.Cai - mailto:caihuanqing@hotmail.com

/***************************************************************************
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Lesser General Public License as published
 *   by the Free Software Foundation; either version 2.1 of the License, or
 *   (at your option) any later version.
 *
 ***************************************************************************/

#region zh-CHS 包含名字空间 | en Include namespace
using System;
using System.Text;
using System.Threading;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Demo_G.O.S.E.ServerEngine.Util;
using Demo_G.O.S.E.ServerEngine.Common;
#endregion

namespace Demo_G.O.S.E.ServerEngine.Network
{
    /// <summary>
    /// 接受到的数据,使用环绕缓冲区来解决粘包和半包的处理
    /// </summary>
    [MultiThreadedSupportgAttribute( "当前的类所有成员都可锁定,支持多线程操作" )]
    public class ReceiveQueue
    {
        #region zh-CHS 类常量 | en Class Constants
        /// <summary>
        /// 字节默认的大小
        /// </summary>
        private const long BUFFER_SIZE = 2048;
        #endregion

        #region zh-CHS 私有成员变量 | en Private Member Variables
        /// <summary>
        /// 字节的头位置
        /// </summary>
        private long m_Head = 0;
        /// <summary>
        /// 字节的尾位置
        /// </summary>
        private long m_Tail = 0;
        /// <summary>
        /// 字节的数组
        /// </summary>
        private byte[] m_Buffer = new byte[BUFFER_SIZE];
        /// <summary>
        /// 
        /// </summary>
        private object m_LockBuffer = new object();
        #endregion

        #region zh-CHS 属性 | en Properties
        #region zh-CHS 私有成员变量 | en Private Member Variables
        /// <summary>
        /// 字节的大小
        /// </summary>
        private long m_Size = 0;
        #endregion
        /// <summary>
        /// 环绕缓冲区内的数据大小
        /// </summary>
        public long Length
        {
            get { return m_Size; }
        }
        #endregion

        #region zh-CHS 方法 | en Method
        /// <summary>
        /// 给出使用环绕缓冲区内的数据
        /// </summary>
        /// <param name="byteBuffer"></param>
        /// <param name="iOffset"></param>
        /// <param name="iSize"></param>
        /// <returns>返回实际读取到的字节数</returns>
        public long Dequeue( ref byte[] byteBuffer, long iOffset, long iSize )
        {
            if ( iSize == 0 )
                return 0;

            if ( iSize > m_Size )
                iSize = m_Size;

            Monitor.Enter( m_LockBuffer );
            {
                if ( m_Head < m_Tail )
                    Buffer.BlockCopy( m_Buffer, (int)m_Head, byteBuffer, (int)iOffset, (int)iSize );
                else
                {
                    long rightLength = m_Buffer.Length - m_Head;

                    if ( rightLength >= iSize )
                        Buffer.BlockCopy( m_Buffer, (int)m_Head, byteBuffer, (int)iOffset, (int)iSize );
                    else
                    {
                        Buffer.BlockCopy( m_Buffer, (int)m_Head, byteBuffer, (int)iOffset, (int)rightLength );
                        Buffer.BlockCopy( m_Buffer, 0, byteBuffer, (int)( iOffset + rightLength ), (int)( iSize - rightLength ) );
                    }
                }

                m_Head = ( m_Head + iSize ) % m_Buffer.Length;
                m_Size -= iSize;

                if ( m_Size == 0 )
                {
                    m_Head = 0;
                    m_Tail = 0;
                }
            }
            Monitor.Exit( m_LockBuffer );

            return iSize;
        }

        /// <summary>
        /// 压入数据至环绕缓冲区内
        /// </summary>
        /// <param name="byteBuffer"></param>
        /// <param name="iOffset"></param>
        /// <param name="iSize"></param>
        public void Enqueue( byte[] byteBuffer, long iOffset, long iSize )
        {
            Monitor.Enter( m_LockBuffer );
            {
                if ( ( m_Size + iSize ) > m_Buffer.Length )
                    SetCapacity( ( m_Size + iSize + 2047 ) & ~2047 ); // 总是以2048的倍数来增大字节数, :( 弄得我老半天才明白原理呢!

                if ( m_Head < m_Tail )
                {
                    long rightLength = m_Buffer.Length - m_Tail;

                    if ( rightLength >= iSize )
                        Buffer.BlockCopy( byteBuffer, (int)iOffset, m_Buffer, (int)m_Tail, (int)iSize );
                    else
                    {
                        Buffer.BlockCopy( byteBuffer, (int)iOffset, m_Buffer, (int)m_Tail, (int)rightLength );
                        Buffer.BlockCopy( byteBuffer, (int)( iOffset + rightLength ), m_Buffer, 0, (int)( iSize - rightLength ) );
                    }
                }
                else
                    Buffer.BlockCopy( byteBuffer, (int)iOffset, m_Buffer, (int)m_Tail, (int)iSize );

                m_Tail = ( m_Tail + iSize ) % m_Buffer.Length;
                m_Size += iSize;
            }
            Monitor.Exit( m_LockBuffer );
        }

        /// <summary>
        /// 压入数据至环绕缓冲区内
        /// </summary>
        /// <param name="byteBuffer"></param>
        /// <param name="iOffset"></param>
        /// <param name="iSize"></param>
        public void Enqueue( IntPtr byteBuffer, long iOffset, long iSize )
        {
            Monitor.Enter( m_LockBuffer );
            {
                if ( ( m_Size + iSize ) > m_Buffer.Length )
                    SetCapacity( ( m_Size + iSize + 2047 ) & ~2047 ); // 总是以2048的倍数来增大字节数, :( 弄得我我半天才明白原理呢!

                IntPtr byteBufferOffset;
                if ( m_Head < m_Tail )
                {
                    long rightLength = m_Buffer.Length - m_Tail;

                    if ( rightLength >= iSize )
                    {
                        byteBufferOffset = new IntPtr( byteBuffer.ToInt64() + iOffset );
                        Marshal.Copy( byteBufferOffset, m_Buffer, (int)m_Tail, (int)iSize );
                    }
                    else
                    {
                        byteBufferOffset = new IntPtr( byteBuffer.ToInt64() + iOffset );
                        Marshal.Copy( byteBuffer, m_Buffer, (int)m_Tail, (int)rightLength );

                        byteBufferOffset = new IntPtr( byteBuffer.ToInt64() + iOffset + rightLength );
                        Marshal.Copy( byteBuffer, m_Buffer, 0, (int)( iSize - rightLength ) );
                    }
                }
                else
                {
                    byteBufferOffset = new IntPtr( byteBuffer.ToInt64() + iOffset );
                    Marshal.Copy( byteBuffer, m_Buffer, (int)m_Tail, (int)iSize );
                }

                m_Tail = ( m_Tail + iSize ) % m_Buffer.Length; // 返回环绕的数据的位置
                m_Size += iSize;
            }
            Monitor.Exit( m_LockBuffer );
        }

        /// <summary>
        /// 清除数据的信息,不清除数据缓冲,用于下次使用
        /// </summary>
        public void Clear()
        {
            Monitor.Enter( m_LockBuffer );
            {
                m_Head = 0;
                m_Tail = 0;
                m_Size = 0;
            }
            Monitor.Exit( m_LockBuffer );
        }

        /// <summary>
        /// 给出数据包的长度
        /// </summary>
        /// <returns></returns>
        public virtual long GetPacketLength()
        {
            long iReturn = 0;

            Monitor.Enter( m_LockBuffer );
            {
                if ( m_Size >= 2 ) // 这是R.O.S.E的实现
                    iReturn = (ushort)( ( m_Buffer[( m_Head ) % m_Buffer.Length] ) | m_Buffer[( m_Head + 1 ) % m_Buffer.Length] << 8 );

                if ( EventPacketLength != null )
                {
                    PacketInfoEventArgs l_EventArgs = new PacketInfoEventArgs( m_Buffer, m_Head );
                    iReturn = EventPacketLength( l_EventArgs );
                }
            }
            Monitor.Exit( m_LockBuffer );

            return iReturn;
        }

        /// <summary>
        /// 给出数据包的ID
        /// </summary>
        /// <returns></returns>
        public virtual long GetPacketID()
        {
            long iReturn = 0;

            Monitor.Enter( m_LockBuffer );
            {
                if ( m_Size >= 2 ) // 这是R.O.S.E的实现
                    iReturn = (ushort)( ( m_Buffer[( m_Head + 2 ) % m_Buffer.Length] ) | m_Buffer[( m_Head + 3 ) % m_Buffer.Length] << 8 );

                if ( EventPacketID != null )
                {
                    PacketInfoEventArgs l_EventArgs = new PacketInfoEventArgs( m_Buffer, m_Head );
                    iReturn = EventPacketID( l_EventArgs );
                }
            }
            Monitor.Exit( m_LockBuffer );

            return iReturn;
        }
        #endregion

        #region zh-CHS 内部方法 | en Internal Methods
        #region zh-CHS 私有成员变量 | en Private Member Variables
        /// <summary>
        /// 当前的类是否已锁
        /// </summary>
        private bool m_bIsLockThis  = false;
        /// <summary>
        /// 当前的类的锁
        /// </summary>
        private object m_LockThis   = new object();
        #endregion
        /// <summary>
        /// 锁定当前的类(表示当前类正在调用中)
        /// </summary>
        /// <returns>返回是否已经锁定成功</returns>
        internal bool Lock()
        {
            bool bReturn = false;

            if ( Monitor.TryEnter( m_LockThis ) == false )
                return false;
            else
            {
                if ( m_bIsLockThis == false ) // 没有锁定
                    bReturn = m_bIsLockThis = true;
            }
            Monitor.Exit( m_LockThis );

            return bReturn;
        }

        /// <summary>
        /// 释放当前已经锁定的类(表示当前类的调用已结束)
        /// </summary>
        internal void Free()
        {
            Monitor.Enter( m_LockThis );
            {
                m_bIsLockThis = false;
            }
            Monitor.Exit( m_LockThis );
        }
        #endregion

        #region zh-CHS 私有方法 | en Private Method
        /// <summary>
        /// 扩大缓冲数据的大小(当前都在锁中操作，因此不需要锁定的)
        /// </summary>
        /// <param name="iCapacity"></param>
        private void SetCapacity( long iCapacity )
        {
            byte[] newBuffer = new byte[iCapacity];

            if ( m_Size > 0 )
            {
                if ( m_Head < m_Tail )
                    Buffer.BlockCopy( m_Buffer, (int)m_Head, newBuffer, 0, (int)m_Size );
                else
                {
                    Buffer.BlockCopy( m_Buffer, (int)m_Head, newBuffer, 0, (int)( m_Buffer.Length - m_Head ) );
                    Buffer.BlockCopy( m_Buffer, 0, newBuffer, (int)( m_Buffer.Length - m_Head ), (int)m_Tail );
                }
            }

            m_Head = 0;
            m_Tail = m_Size;
            m_Buffer = newBuffer;
        }
        #endregion

        #region zh-CHS 静态事件 | en Static Event
        /// <summary>
        /// 获取接收到的数据包长度
        /// </summary>
        public static event PacketLengthEventHandler EventPacketLength;
        /// <summary>
        /// 获取接收到的数据包ID
        /// </summary>
        public static event PacketIDEventHandler EventPacketID;
        #endregion
    }
}
#endregion

